#include "beesolver.h"
#include <QDebug>
#include <windows.h>
#include <omp.h>
#include <time.h>
int SolverBeeAlgorithm::bees = 25;
int SolverBeeAlgorithm::bBees = 5;
int SolverBeeAlgorithm::eBees = 10;
int SolverBeeAlgorithm::bSources = 10;
int SolverBeeAlgorithm::eSources = 5;
int SolverBeeAlgorithm::iterations = 8;

BeeSolver::BeeSolver(sameGame &sg):
    game(sg),copy_of_game(&sg)
{
    int gs = game.getGroups().size();
    while(gs>0)
    {
        int selectedGroup = rand()%gs;
        steps.push_back(game.getGroups()[selectedGroup]);
        game.click(game.getGroups().at(selectedGroup).x,game.getGroups().at(selectedGroup).y);
        gs = game.getGroups().size();
    }
    result = game.getResult();
    score = game.getScore();
}
BeeSolver::BeeSolver(BeeSolver &bee):
    game(*bee.copy_of_game),copy_of_game(bee.copy_of_game),steps(bee.steps),result(bee.result),score(bee.score)
{

}
void BeeSolver::searchInNeighborhood()
{
    std::vector<SGPoint> newv;
    if(steps.size()>0)
    {
        int q = rand()%(steps.size());
        int i;

        for(i=0;i<q;i++)
        {
            newv.push_back(steps.at(i));
            game.click(steps.at(i).x,steps.at(i).y);

        }
    }
    int gs = game.getGroups().size();
    while(gs>0)
    {
        int selectedGroup = rand()%gs;
        newv.push_back(game.getGroups()[selectedGroup]);
        game.click(game.getGroups().at(selectedGroup).x,game.getGroups().at(selectedGroup).y);
        gs = game.getGroups().size();
    }
    steps.clear();
    steps = newv;
    result = game.getResult();
    score = game.getScore();
}
SGSolution SolverBeeAlgorithm::solve(sameGame sg)
{
    std::vector<BeeSolver*> b(bees);
    std::vector<BeeSolver*> eb(eBees);
    std::vector<BeeSolver*> bb(bBees);
    int i=0;
    srand(time(0));
#pragma omp parallel for shared(b,sg) private(i) schedule(dynamic)
    for(i=0;i<bees;++i)
    {
        b[i]=(new BeeSolver(sg));
    }
    std::sort(b.begin(),b.end(),sortBees);

    for(int iteration=0;iteration<iterations;iteration++)
    {
        for(i=0;i<eSources;++i)
        {
            int p;
#pragma omp parallel for shared(eb,b,i,eBees) private(p) schedule(dynamic)
            for(p=0;p<eBees;p++)
            {
                eb[p] = new BeeSolver(*b[i]);
                eb[p]->searchInNeighborhood();
            }

            std::sort(eb.begin(),eb.end(),sortBees);

            if(b[i]->result > eb[0]->result )
            {
                delete b[i];
                b[i] = new BeeSolver(*eb[0]);

            }

            for(p=0;p<eb.size();p++)
            {
                delete eb.at(p);
            }

        }
        for(i=eSources;i<(eSources+bSources);++i)
        {
            int p;
#pragma omp parallel for shared(bb,b,i,bBees) private(p) schedule(dynamic)
            for(p=0;p<bBees;p++)
            {
                // bb.push_back();
                bb[p] = new BeeSolver(*b.at(i));
                bb[p]->searchInNeighborhood();
            }
            std::sort(bb.begin(),bb.end(),sortBees);
            if(b.at(i)->result > bb.at(0)->result )
            {
                delete b[i];
                b[i] = new BeeSolver(*bb[0]);
            }
#pragma omp parallel for shared(bb) private(p) schedule(dynamic)
            for(p=0;p<bb.size();p++)
            {
                delete bb[p];
            }
        }
#pragma omp parallel for shared(b,eSources,bSources,sg) private(i) schedule(dynamic)
        for(i=(eSources+bSources);i<b.size();++i)
        {
            delete b[i];
            b[i] = new BeeSolver(sg);
        }

        std::sort(b.begin(),b.end(),sortBees);

        qDebug() << iteration << b[0]->score << b[0]->result;
    }


    bestBee = new BeeSolver(*b.at(0));

    int p;
    sumScore = 0;
#pragma omp parallel for shared(b) private(p)
    for(p=0;p<b.size();p++)
    {
        //
        sumScore+=b[p]->score;
        delete b[p];
    }
    //b.clear();
    SGSolution solution;
    solution.steps.assign(bestBee->steps.begin(),bestBee->steps.end());
    solution.score = bestBee->score;
    solution.BlocksLefted = bestBee->result;

    return solution;
}



bool sortBees(const BeeSolver* b1, const BeeSolver* b2)
{
    if(b1->score==b2->score)
    {
        if(b1->result == b2->result)
        {
            return b1->steps.size() < b2->steps.size();
        }
        return b1->result < b2->result;
    }
    return b1->score > b2->score;
}

SolverBeeAlgorithm::SolverBeeAlgorithm()
{

}
